#include "clientSession.hh"
#include <string>
#include <utility>
#include <string.h>

void clientSession::start()
{
	// read uuid
	try {
		char aBuf[32] = "";
		boost::asio::read(mySocket,boost::asio::buffer(aBuf,1));
		int len = (int)(aBuf[0]);
		// int len = boost::lexical_cast<int>(aBuf);
		memset(aBuf,0,32);
		boost::asio::read(mySocket,boost::asio::buffer(aBuf,len));
		myUUID = aBuf;
	} catch (boost::system::system_error& e) {
		DEBUG_ERROR("[clientSession::start] not read uuid. error.message = " << e.what());
	}

	mySocket.async_read_some(boost::asio::buffer(myHead,sizeof(dataHead)),
			myStrand.wrap(boost::bind(&clientSession::handle_read_head,shared_from_this(),0,
				boost::asio::placeholders::error,
				boost::asio::placeholders::bytes_transferred)));
}
void clientSession::sendPluginUUID(const string& thePluginUUID)
{
	int aUUIDLen = thePluginUUID.size();
	string aStr((char*)(&aUUIDLen),sizeof(aUUIDLen));
	aStr.append(thePluginUUID);
	clientSession::write(aStr);
}

void clientSession::write(const string& theStr)
{
	dataHead aDataHead;
	memset(&aDataHead,0,sizeof(aDataHead));
	aDataHead._dataLen = theStr.length();

	string aStr((char*)(&aDataHead),sizeof(aDataHead));
	aStr.append(theStr);

	try {
		boost::asio::write(mySocket,boost::asio::buffer(aStr));
	} catch (boost::system::system_error& e) {
		DEBUG_ERROR("[clientSession::write] not send message = "<< theStr << ".error.message = " << e.what());
		throw e;
	}
}

void clientSession::async_write(const string& theStr)
{
	dataHead aDataHead;
	memset(&aDataHead,0,sizeof(aDataHead));
	aDataHead._dataLen = theStr.length();

	string aStr((char*)(&aDataHead),sizeof(aDataHead));
	aStr.append(theStr);

	try {
		boost::asio::async_write(mySocket,boost::asio::buffer(aStr),
				boost::bind(&clientSession::handle_write,shared_from_this(),
					boost::asio::placeholders::error,boost::asio::placeholders::bytes_transferred));
	} catch (boost::system::system_error& e) {
		DEBUG_ERROR("[clientSession::async_write] not send message = "<< theStr << ".error.message = " << e.what());
		throw e;
	}
}

void clientSession::handle_write(const boost::system::error_code& ec,size_t len)
{
	if (ec) {
		DEBUG_INFO("[clientSession::handle_write] error_code.msg= "<< ec.message());
		cleanData();
		mySocket.close();
	}
}

void clientSession::handle_read_head(int __allRecevieHeadLen,const boost::system::error_code& error,std::size_t len)
{
	// static int __allRecevieHeadLen = 0;
	__allRecevieHeadLen += len;

	do {
		if (!error) {
			if (__allRecevieHeadLen < sizeof(dataHead)) {
				DEBUG_INFO("[clientSession::handle_read_head] (len+strlen(myHead)) < sizeof(dataHead);");
				DEBUG_INFO("[clientSession::handle_read_head] len = " << len);
				mySocket.async_read_some(boost::asio::buffer(myHead+__allRecevieHeadLen,
							sizeof(dataHead)-__allRecevieHeadLen),
						myStrand.wrap(boost::bind(&clientSession::handle_read_head,shared_from_this(),
							__allRecevieHeadLen,
							boost::asio::placeholders::error,
							boost::asio::placeholders::bytes_transferred)));
			} else if (__allRecevieHeadLen == sizeof(dataHead)) {
				DEBUG_INFO("[clientSession::handle_read_head] (len+strlen(myHead)) == sizeof(dataHead);");
				dataHead __dataHead;
				memcpy(&__dataHead,myHead,sizeof(__dataHead));
				DEBUG_INFO("[clientSession::handle_read_head] __dataHead._version="<<__dataHead._version);
				DEBUG_INFO("[clientSession::handle_read_head] __dataHead._reqID="<<__dataHead._reqID);
				DEBUG_INFO("[clientSession::handle_read_head] __dataHead._reqType="<<__dataHead._reqType);
				DEBUG_INFO("[clientSession::handle_read_head] __dataHead.__dataLen="<<__dataHead._dataLen);
				__allRecevieHeadLen = 0;
				memset(myData,0,max_len);
				mySocket.async_read_some(boost::asio::buffer(myData,__dataHead._dataLen),
						myStrand.wrap(boost::bind(&clientSession::handle_read,shared_from_this(),
							__allRecevieHeadLen,
							boost::asio::placeholders::error,
							boost::asio::placeholders::bytes_transferred)));
			} else {
				DEBUG_INFO("[clientSession::handle_read_head] (len+strlen(myHead)) > sizeof(dataHead);");
				// write_log(E_LOG_INFO,"[client::handle_read_head] (len+strlen(myHead)) > sizeof(dataHead),the msg will throw away");
				__allRecevieHeadLen = 0;
				cleanData();
				mySocket.async_read_some(boost::asio::buffer(myHead,sizeof(dataHead)),
						myStrand.wrap(boost::bind(&clientSession::handle_read_head,shared_from_this(),
							__allRecevieHeadLen,
							boost::asio::placeholders::error,
							boost::asio::placeholders::bytes_transferred)));
			}
		} else {
			DEBUG_INFO("[clientSession::handle_read_head] error.message = " << error.message());
			// write_log(E_LOG_INFO,"[client::handle_read_head] error.message = " << error.message());
			__allRecevieHeadLen = 0;
			cleanData();
			mySocket.close();
		}	
	} while(0);
}

void clientSession::handle_read(int __allRecevieDataLen,const boost::system::error_code& error,std::size_t len)
{
	DEBUG_INFO("[clientSession::handle_read] begin");
	// static int __allRecevieDataLen = 0;
	__allRecevieDataLen += len;

	do {
		dataHead __dataHead;
		memcpy(&__dataHead,myHead,sizeof(__dataHead));

		if (!error) {
			if (__allRecevieDataLen < __dataHead._dataLen) {
				DEBUG_INFO("[clientSession::handle_read] (len+strlen(myData)) < __dataHead._dataLen;");
				DEBUG_INFO("[clientSession::handle_read] len = " << len);
				mySocket.async_read_some(boost::asio::buffer(myData+__allRecevieDataLen,
							__dataHead._dataLen-__allRecevieDataLen),
						myStrand.wrap(boost::bind(&clientSession::handle_read,shared_from_this(),
							__allRecevieDataLen,
							boost::asio::placeholders::error,
							boost::asio::placeholders::bytes_transferred)));
			} else if (__allRecevieDataLen == __dataHead._dataLen) {
				DEBUG_INFO("[clientSession::handle_read] (len+strlen(myData)) == __dataHead._dataLen;");
				__allRecevieDataLen = 0;
				recevied();
				mySocket.async_read_some(boost::asio::buffer(myHead,sizeof(dataHead)),
						myStrand.wrap(boost::bind(&clientSession::handle_read_head,shared_from_this(),
							__allRecevieDataLen,
							boost::asio::placeholders::error,
							boost::asio::placeholders::bytes_transferred)));
			} else {
				DEBUG_INFO("[clientSession::handle_read] (len+strlen(myData)) > __dataHead._dataLen;");
				// write_log(E_LOG_INFO,"[client::handle_read] (len+strlen(myData)) > __dataHead._dataLen,the msg will throw away");
				__allRecevieDataLen = 0;
				cleanData();
				mySocket.async_read_some(boost::asio::buffer(myHead,sizeof(dataHead)),
						myStrand.wrap(boost::bind(&clientSession::handle_read_head,shared_from_this(),
							__allRecevieDataLen,
							boost::asio::placeholders::error,
							boost::asio::placeholders::bytes_transferred)));
			}
		} else {
			DEBUG_INFO("[clientSession::handle_read] error.message = " << error.message());
			// write_log(E_LOG_INFO,"[client::handle_read] error.message = " << error.message());
			__allRecevieDataLen = 0;
			cleanData();
			mySocket.close();
		}	
	} while(0);
	DEBUG_INFO("[clientSession::handle_read] end");
}

void clientSession::recevied()
{
	// DEBUG_INFO("[clientSession::recevied] start");

	dataHead __dataHead;
	memcpy(&__dataHead,myHead,sizeof(__dataHead));

	Message* __pMsg = (Message*)malloc(sizeof(Message));
	assert(__pMsg);
	memset(__pMsg,0,sizeof(Message));    
	__pMsg->chType = 0;
	__pMsg->chErrorCode = 0;
	__pMsg->chMsgHeadNo = __dataHead._reqType;
	__pMsg->reqID = __dataHead._reqID;
	__pMsg->strMsgInfo = (char*)(malloc(__dataHead._dataLen+1));
	memset(__pMsg->strMsgInfo,0,__dataHead._dataLen+1);
	memcpy(__pMsg->strMsgInfo,myData,__dataHead._dataLen);
	// __pMsg->strMsgInfo.append(myData,strlen(myData));

	// std::cout << "[clientSession::recevied] strMsgInfo=" << __pMsg->strMsgInfo << std::endl;
	// extern std::queue<Message> requestDataQueue;
	// extern boost::unique_lock<boost::shared_mutex> requestDataQueueLock;
	// requestDataQueueLock.lock();
	// requestDataQueue.push(*__pMsg);
	// requestDataQueueLock.unlock();

	// extern boost::condition_variable requestDataCondition;
	// requestDataCondition.notify_one();
	myNetworkCallback(boost::lexical_cast<string>(myUUID),
			boost::lexical_cast<string>(myData));

	// xlib_free(__pMsg);
	free(__pMsg->strMsgInfo);
	free(__pMsg);

	cleanData();
	// DEBUG_INFO("[clientSession::recevied] end");
}
